package pers.cz.transform;

import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.LoaderClassPath;

import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;

/**
 * @program: postgirl-collection-client
 * @description: ParamsAndReurnTransformer
 * @author: Cheng Zhi
 * @create: 2022-03-01 18:08
 **/
public class ParamsAndReurnEasyFrameTransformer implements ITransformer{

    public final String TEST_CLASS_NAME = "jef.database.AbstractDbClient";                           // easyframe

    public final String[] METHOD_NAMES = {"innerSelect","insert","delete","update"};                 // easyframe

    public static final String SELECT = "innerSelect";
    public static final String INSERT = "insert";
    public static final String DELETE = "delete";
    public static final String UPDATE = "update";
    @Override
    public void doInert(String... params) {

    }

    @Override
    public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
        String finalClassName = className.replace("/", ".");
        if (finalClassName.equals(TEST_CLASS_NAME)) {
            // 动态修改代码
            try {
                ClassPool classPool = new ClassPool(true);
                classPool.insertClassPath(new LoaderClassPath(loader));
                // 获取目标类
                CtClass ctClass = classPool.get(TEST_CLASS_NAME);
                // 获取要监听的方法
                CtMethod[] declaredMethods = ctClass.getDeclaredMethods();

                for (int i=0; i<declaredMethods.length; i++) {
                    // FIXME 这里需要注意，这几个方法的插码顺序要从大到小排列，避免先插码的影响后续的行数。
                    // 查询
                    if (declaredMethods[i].getName().startsWith(SELECT)) {
                        String src = "{" +
                                " Object responseMock = pers.cz.mock.ParamsAndReturnMock.begin(resultClz, sql);" +
                                " if (responseMock != null) {" +
                                "       System.out.println(\"-----直接返回，不查询真实的数据库---\");" +
                                "       return (java.util.List)responseMock;" +
                                "}" +
                                "}";
                        declaredMethods[i].insertAt(1281, src);
                        declaredMethods[i].insertAt(1328, getSelectSrc(declaredMethods[i].getName()));
                    }

                    // 修改
                    if (declaredMethods[i].getName().equals(UPDATE) && declaredMethods[i].getParameterTypes().length == 2) {
                        String src = "{" +
                                " Object responseMock = pers.cz.mock.ParamsAndReturnMock.begin(obj, obj);" +
                                " if (responseMock != null) {" +
                                "       System.out.println(\"-----直接返回，不查询真实的数据库---\");" +
                                "       return (int)responseMock;" +
                                "}" +
                                "}";
                        //declaredMethods[i].insertAt(627, src);
                        declaredMethods[i].insertAt(643, getUpdateSrc());
                    }

                    // 删除
                    if (declaredMethods[i].getName().equals(DELETE) && declaredMethods[i].getParameterTypes().length == 2) {
                        String src = "{" +
                                " Object responseMock = pers.cz.mock.ParamsAndReturnMock.begin(obj, obj);" +
                                " if (responseMock != null) {" +
                                "       System.out.println(\"-----直接返回，不查询真实的数据库---\");" +
                                "       return (int)responseMock;" +
                                "}" +
                                "}";
                        //declaredMethods[i].insertAt(582, src);
                        declaredMethods[i].insertAt(597, getDeleteSrc());
                    }

                    // 插入
                    if (declaredMethods[i].getName().equals(INSERT) && declaredMethods[i].getParameterTypes().length == 3) {
                        String src = "{" +
                                " Object responseMock = pers.cz.mock.ParamsAndReturnMock.begin(null, obj);" +
                                " if (responseMock != null) {" +
                                "       System.out.println(\"-----直接返回，不查询真实的数据库---\");" +
                                "       return;" +
                                "}" +
                                "}";
                        declaredMethods[i].insertAt(509, src);
                        declaredMethods[i].insertAt(512, getInsertSrc());
                    }
                }
                // 加载到jvm
                return ctClass.toBytecode();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    /**
     * 查询，sql,返回集合
     * @param targetMethodName
     * @return
     */
    private String getSelectSrc(String targetMethodName) {

        String src2 = "{" +
                "String method = Thread.currentThread().getStackTrace()[1].getMethodName();" +
                "pers.cz.mock.ParamsAndReturnMock.end(method, sql, list, method);" +
                "}";
        return src2;
    }

    /**
     * 删除 表名，参数，返回值
     * @return
     */
    private String getDeleteSrc() {
        String src = "{" +
                "String method = Thread.currentThread().getStackTrace()[1].getMethodName();" +
                "pers.cz.mock.ParamsAndReturnMock.end(myTableName, obj, Integer.valueOf(count), method);" +
                "}";

        return src;
    }

    /**
     * 修改 表名，参数，返回值
     * @return
     */
    private String getUpdateSrc() {
        String src = "{" +
                "String method = Thread.currentThread().getStackTrace()[1].getMethodName();" +
                "pers.cz.mock.ParamsAndReturnMock.end(myTableName, obj, Integer.valueOf(n), method);" +
                "}";

        return src;
    }

    /**
     * 插入比较特殊没有返回值
     * @return
     */
    private String getInsertSrc() {
        String src = "{" +
                "String method = Thread.currentThread().getStackTrace()[1].getMethodName();" +
                "pers.cz.mock.ParamsAndReturnMock.end(myTableName, obj, obj, method);" +
                "}";

        return src;
    }
}
